package seismosurfer.gui.panel;

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;

import seismosurfer.data.QuakeMaxMinData;
import seismosurfer.data.constants.ParameterNames;
import seismosurfer.data.constants.QueryNames;
import seismosurfer.gui.GUIConstants;
import seismosurfer.gui.menu.QueryMenu;
import seismosurfer.layer.QuakeLayer;

import com.bbn.openmap.MapBean;
import com.bbn.openmap.gui.OMComponentPanel;

/**
 * The "Nearest-Neighbour Query" panel.
 *
 */
public class NNQueryPanel extends OMComponentPanel implements
        PropertyChangeListener, ParameterNames, QueryNames, Serializable,
        GUIConstants {
    
    private static final long serialVersionUID = -3444561045483815033L;

    private MapBean map = null;

    private QuakeLayer ql = null;

    double initlat, initlong;

    double minLat, minLong, maxLat, maxLong;

    // Spin Buttons for selecting a lat/lon point to find its NNs and
    // for selecting the number of NNs to be retrieved.
    protected JSpinner PLat, PLong, NofNN, PMag;

    protected SpinnerNumberModel LongSpinModel, LatSpinModel, MagSpinModel,
            NofNNSpinModel;    

    public NNQueryPanel(ActionListener buttonsListener) {
        super();
        createPanel(buttonsListener);
    }

    protected void createPanel(ActionListener buttonsListener) {

        try {

            // These are useful for getting min, max values from the DB
            // for the SpinButtons and the Date Selectors.

            double min, max;

            // A Panel to hold the controls
            JPanel NNQPane = new JPanel();
            GridBagLayout NNQPaneLayout = new GridBagLayout();
            NNQPane.setLayout(NNQPaneLayout);
            GridBagConstraints c = new GridBagConstraints();

            JLabel Label1 = new JLabel("Point to find its Nearest Neighbors:");
            c.gridx = 0;
            c.gridy = 0;
            c.gridwidth = GridBagConstraints.REMAINDER;
            NNQPaneLayout.setConstraints(Label1, c);
            NNQPane.add(Label1);

            JLabel LatLabel = new JLabel("lat");

            min = QuakeMaxMinData.getDBMinLatitude();
            max = QuakeMaxMinData.getDBMaxLatitude();

            LatSpinModel = new SpinnerNumberModel((min + max) / 2, min, max,
                    0.1);
            PLat = new JSpinner(LatSpinModel);

            JLabel LongLabel = new JLabel("lon");

            min = QuakeMaxMinData.getDBMinLongitude();
            max = QuakeMaxMinData.getDBMaxLongitude();

            LongSpinModel = new SpinnerNumberModel((min + max) / 2, min, max,
                    0.1);
            PLong = new JSpinner(LongSpinModel);

            JPanel p1 = new JPanel();
            p1.setLayout(new BoxLayout(p1, BoxLayout.X_AXIS));
            p1.add(LatLabel);
            p1.add(PLat);
            p1.add(LongLabel);
            p1.add(PLong);
            c.gridx = 0;
            c.gridy = 1;
            NNQPaneLayout.setConstraints(p1, c);
            NNQPane.add(p1);

            JLabel BlankLabel5 = new JLabel("     ");
            c.gridx = 0;
            c.gridy = 2;
            NNQPaneLayout.setConstraints(BlankLabel5, c);
            NNQPane.add(BlankLabel5);

            JLabel MagLabel = new JLabel(
                    "Filter results by magnitude greater than:");
            c.gridx = 0;
            c.gridy = 6;
            NNQPaneLayout.setConstraints(MagLabel, c);
            NNQPane.add(MagLabel);

            MagSpinModel = new SpinnerNumberModel(4.0, 0.0, 7.5, 0.5);
            PMag = new JSpinner(MagSpinModel);
            c.gridx = 0;
            c.gridy = 7;
            NNQPaneLayout.setConstraints(PMag, c);
            NNQPane.add(PMag);

            JLabel BlankLabel1 = new JLabel("     ");
            c.gridx = 0;
            c.gridy = 5;
            NNQPaneLayout.setConstraints(BlankLabel1, c);
            NNQPane.add(BlankLabel1);

            JLabel Label3 = new JLabel("Number of NN to retrive:");
            c.gridx = 0;
            c.gridy = 3;
            NNQPaneLayout.setConstraints(Label3, c);
            NNQPane.add(Label3);

            NofNNSpinModel = new SpinnerNumberModel(1, 1, 999, 10);
            NofNN = new JSpinner(NofNNSpinModel);
            c.gridx = 0;
            c.gridy = 4;
            NNQPaneLayout.setConstraints(NofNN, c);
            NNQPane.add(NofNN);

            JLabel BlankLabel2 = new JLabel("     ");
            c.gridx = 0;
            c.gridy = 8;
            NNQPaneLayout.setConstraints(BlankLabel2, c);
            NNQPane.add(BlankLabel2);

            // bottomPanel consists of 2 buttons: OK and Cancel.
            JPanel bottomPanel = new JPanel();
            bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.X_AXIS));
            JButton b1 = new JButton("OK");
            b1.addActionListener(buttonsListener);
            b1.setActionCommand(OK);
            bottomPanel.add(b1);

            JButton b2 = new JButton("Cancel");
            b2.addActionListener(buttonsListener);
            b2.setActionCommand(CANCEL);
            bottomPanel.add(b2);

            // setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);
            // Container contentPane = getContentPane();
            GridBagLayout contentPaneLayout = new GridBagLayout();
            GridBagConstraints ccP = new GridBagConstraints();
            setLayout(contentPaneLayout);
            ccP.gridx = 0;
            ccP.gridy = 0;
            contentPaneLayout.setConstraints(NNQPane, ccP);
            add(NNQPane);
            ccP.gridx = 0;
            ccP.gridy = 1;
            contentPaneLayout.setConstraints(bottomPanel, ccP);
            add(bottomPanel);
            setLayout(contentPaneLayout);

        } catch (Exception e) {
            e.printStackTrace();
            System.out.println(e.getMessage());
        }

    }

    public void sendQueryParameters() {

        Map parameters = new HashMap();

        parameters.put(MAG_MIN, (Double) MagSpinModel.getNumber());

        parameters.put(LONG, (Double) LongSpinModel.getNumber());
        parameters.put(LAT, (Double) LatSpinModel.getNumber());

        parameters.put(ROWNUM, (Integer) NofNNSpinModel.getNumber());

        parameters.put(SOURCE, getSource());

        if (ql != null) {
            ql.loadQuakeClientData(QueryNames.NN, parameters);
        } else {
            System.out.println("NULL Layer!!!");
        }

    }

    public void updateDialogValues(double latitude, double longitude) {
        setMinMaxCoords();
        setCoordinates(latitude, longitude);
    }

    public void updateDialogValues() {
        setMinMaxCoords();
        setCoordinates();
    }

    protected void setCoordinates() {
        if (map != null) {
            initlat = map.getCenter().getLatitude();
            LatSpinModel.setValue(new Double(initlat));

            initlong = map.getCenter().getLongitude();
            LongSpinModel.setValue(new Double(initlong));
        }
    }

    protected void setCoordinates(double latitude, double longitude) {

        if (latitude <= maxLat && latitude >= minLat) {
            initlat = latitude;
            LatSpinModel.setValue(new Double(initlat));
        } else {
            setCoordinates();
            return;
        }

        if (longitude <= maxLong && longitude >= minLong) {
            initlong = longitude;
            LongSpinModel.setValue(new Double(initlong));
        } else {
            setCoordinates();
            return;
        }
    }

    protected void setMinMaxCoords() {
        if (map != null) {
            minLat = ((map.getProjection()).getLowerRight()).getLatitude();
            maxLat = ((map.getProjection()).getUpperLeft()).getLatitude();
            LatSpinModel.setMinimum(new Double(minLat));
            LatSpinModel.setMaximum(new Double(maxLat));

            minLong = ((map.getProjection()).getUpperLeft()).getLongitude();
            maxLong = ((map.getProjection()).getLowerRight()).getLongitude();

            LongSpinModel.setMinimum(new Double(minLong));
            LongSpinModel.setMaximum(new Double(maxLong));
        }
    }

    public void findAndInit(Object someObj) {

        if (someObj instanceof QuakeLayer) {
            ql = (QuakeLayer) someObj;
        }

        if (someObj instanceof MapBean) {
            map = (MapBean) someObj;
        }
    }

    public void findAndUndo(Object someObj) {

        if (someObj instanceof MapBean && map == someObj) {
            map = null;
        }
    }

    public void propertyChange(PropertyChangeEvent e) {
        if (e.getPropertyName().equalsIgnoreCase(QueryMenu.SourceProperty)) {
            setSource((String) e.getNewValue());
        }
    }

    public String getSource() {
        return source;
    }

    public void setSource(String source) {
        this.source = source;
    }

    private String source;

}
